LIBRARY IEEE;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;

ENTITY alu IS
    PORT(A, B : IN SIGNED(15 DOWNTO 0);
        F : IN STD_LOGIC_VECTOR(2 DOWNTO 0);
        Y : OUT SIGNED(15 DOWNTO 0);
        N,V,Z : OUT STD_LOGIC);
END alu;

ARCHITECTURE a OF alu IS
    FUNCTION ISOVERFLOW(
        CONSTANT A, B, R : SIGNED(15 DOWNTO 0)
    ) RETURN STD_LOGIC IS
        VARIABLE RETVAL : STD_LOGIC;
    BEGIN
        IF ((A(15) AND B(15) AND NOT R(15))
            OR
           (NOT A(15) AND NOT B(15) AND R(15))) = '1' THEN
            RETVAL := '1';
        ELSE
            RETVAL := '0';
        END IF;
        RETURN RETVAL;
    END FUNCTION;

BEGIN
    PROCESS (A,B,F)
        VARIABLE RETVAL : SIGNED(15 DOWNTO 0);
    BEGIN
        V <= '0';
        IF F = "000" THEN    -- Addition
            RETVAL := A + B;
            V <= ISOVERFLOW(A,B,RETVAL);
        ELSIF F = "001" THEN -- Subtraction
            RETVAL := A - B;
            V <= ISOVERFLOW(A,-B,RETVAL);
        ELSIF F = "010" THEN -- LSL
            RETVAL := A(14 DOWNTO 0) & '0';
        ELSIF F = "011" THEN -- LSR
            RETVAL := '0' & A(15 DOWNTO 1);
        ELSIF F = "100" THEN -- XOR
            RETVAL := SIGNED(STD_LOGIC_VECTOR(A) XOR STD_LOGIC_VECTOR(B));
        ELSIF F = "101" THEN -- COM
            RETVAL := SIGNED(NOT STD_LOGIC_VECTOR(A));
        ELSIF F = "110" THEN -- NEG
            RETVAL := 0 - A;
            IF STD_LOGIC_VECTOR(RETVAL) = "1000000000000000" THEN
                V <= '1';
            END IF;
        ELSE                 -- CLR
            RETVAL := "0000000000000000";
        END IF;
        IF STD_LOGIC_VECTOR(RETVAL) = "000000000000000" THEN
            Z <= '1';
        ELSE
            Z <= '0';
        END IF;
        IF RETVAL(15) = '1' THEN
            N <= '1';
        ELSE
            N <= '0';
        END IF;

        Y <= RETVAL;
    END PROCESS;
END ARCHITECTURE a;
